///////////////////////////////////////////////////////////////
// e_tutorial.cpp : Tutorial Application, Lessons 1..3
//
// Link acknex.lib to your project, and use WED to create
// an acknex.dll engine release version for your EXE.
///////////////////////////////////////////////////////////////
// Include the usual Windows headers
#define WIN32_LEAN_AND_MEAN		
#include <windows.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

// Include the engine data types, variables, and functions
#include "adll.h"

#define Lesson1
//#define Lesson2
//#define Lesson3

#ifdef Lesson1
///////////////////////////////////////////////////////////////
// Lesson 1: Writing an application with just four lines of C
///////////////////////////////////////////////////////////////
// This is the Windows main function. It's executed at start
// of the application. Don't be confused by the scary looking 
// arguments, we normally won't need any.

int APIENTRY WinMain(HINSTANCE hInstance,	// application instance handle
                     HINSTANCE hPrevInstance, // always zero
                     LPTSTR    lpCmdLine,	// application command line
                     int       nCmdShow)	// window flags
{
// If you're used to windows programming, you would normally expect
// here about 150 lines of window definition, class registration, 
// and message loop stuff. You can do that if you want and override
// the engine defaults, but all you really need is:

	engine_open("arena.wmb");

// The engine_open() function initializes the GameStudio engine,
// and accepts a command line string with the name of a script, 
// or an entity file to be loaded upon initialization. For instance, 
// we could hand over the application command line (char*)lpCmdLine.
// We could also pass options to start in client or server mode.
// Here we're just loading the arena level. 
	
// After loading a level we're ready to render it. The engine_frame() 
// function executes the scripts and physics, and renders the 
// current camera position to the screen if a level is loaded. 
// The function returns zero when a script calls exit() or an Abort 
// button is clicked. 

	while (engine_frame()); 

// For rendering the level, we are just repeating engine_frame() until 
// a 0 value is returned. This is normally our main loop, all 
// the interesting stuff happens here. However, when an entity file 
// name is given for engine_open(), the engine acts as a viewer.
// A default walkthrough movement is activated and we don't want 
// to do anything else at the moment.

	engine_close();

// Someone pressed the Exit icon. Our application is about to end. 
// Before that, the engine must be closed by engine_close().

	return 0;
}
#endif // Lesson1 /////////////////////////////////////////////



#ifdef Lesson2
///////////////////////////////////////////////////////////////
// Lesson2: Using engine variables and functions
///////////////////////////////////////////////////////////////

int APIENTRY WinMain(HINSTANCE hInstance,	
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,	
                     int       nCmdShow)	
{
// The engine_open() function returns a pointer to a struct of 
// engine variables. We don't want to load a script or level here, 
// so we just pass NULL.
	
	ENGINE_VARS *ev = engine_open(NULL);

// Once we have the pointer to the ENGINE_VARS struct, we can use engine 
// functions for customizing the window, giving a level name to load, 
// assigning functions to buttons etc.
// In our case we're now again loading the arena.wmb level. 

	level_load("arena.wmb");

// We want to limit our frame rate to 50 frames per second. For this we
// change an engine variable named fps_max:

    SETV(fps_max,50);

// SETV() is a convenient macro to set engine variables.
// It is defined in the adll.h header.

// Now let's enter our main loop:

	while (engine_frame()) 
	{

// The first engine frame opens the DirectX device and 
// switches the engine window to DirectX mode. Therefore,
// the time before the first frame is merely for setting 
// or defining variables - DirectX functions won't work yet.
// Also the the level is actually loaded in the first frame.
// The level_load() function just stored its name.
// If we loaded a script before, it's main and starter 
// functions are also executed in the first engine_frame().

// We didn't pass a level name to engine_open(), so we now have to 
// program our own camera movement. 
// By default, a VIEW named "camera" is created when opening a level,
// and can be moved by changing it's angle and position parameters.

		v(camera).pan += 3 * v(key_force).x;	// left/right cursor keys
		v(camera).tilt += 3 * v(key_force).y;	// up/down cursor keys

// The key_force vector returns a value of +/-1 dependent on which 
// cursor keys in x and y direction are pressed. 
// The v() is another simple macro to access engine variables.

// Now we want to move in the direction the camera is looking.
// For movement with the WASD keys, we use the key_w, key_a, 
// key_s, key_d variables and calculate a movement vector.

		VECTOR vMove;	// movement vector
		vMove.x = 6.0 * (v(key_w) - v(key_s));	// forward
		vMove.y = 6.0 * (v(key_a) - v(key_d));	// sideward
		vMove.z = 0;

// Finally, we use engine vector functions to rotate the movement vector 
// by the camera angle, then add it to the camera position. 
// We can typecast any object's x position to a VECTOR and it's pan 
// orientation to an Euler ANGLE.

		vec_rotate (&vMove, (ANGLE*)&v(camera).pan);
		vec_add ((VECTOR*)&v(camera).x, &vMove);
	}

// This simple movement was not as smooth as the default one, 
// but we're going to change this in our next lesson.

	engine_close();
	return 0;
}
#endif // Lesson2 /////////////////////////////////////////////

#ifdef Lesson3
///////////////////////////////////////////////////////////////
// Lesson3: Physics engine and event functions 
///////////////////////////////////////////////////////////////
// some global definitions - we'll use them later
ENGINE_VARS *ev;
ENTITY *eBall;
void Kick(void);
void Plop(void);

///////////////////////////////////////////////////////////////
int APIENTRY WinMain(HINSTANCE hInstance,	
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,	
                     int       nCmdShow)	
{
	ev = engine_open(NULL);

// We add some folders that contain our media files -
// replace them by your own folders!

	add_folder("c:\\project\\acknex\\ackwed\\work\\");
	add_folder("c:\\project\\acknex\\ackwed\\template\\");
	
// Activate stencil shadows - they are a 'redefine' variable 
// that has to be set before the first engine frame -
// and set the sound at full volume.

	SETV(shadow_stencil,ON);
	SETV(sound_vol,100);

// Create the required splash screen panel at layer 1.
// The panel definition only contains a single bmap here.
// Engine functions use variables of type var, so we
// precede all number arguments with the _VAR macro.

	PANEL* pSplash = pan_create("bmap = logolite.pcx;",_VAR(1));

// Scale the panel by the screen to bmap size ratio
// in order to fit the screen, and make it visible.

	pSplash->scale_x = _VAR((float)v(screen_size).x / bmap_width(pSplash->bmap));
	pSplash->scale_y = _VAR((float)v(screen_size).y / bmap_height(pSplash->bmap));
	pSplash->flags |= VISIBLE;

// After a panel is set to VISIBLE, we have to wait 3 frames
// until we can really see it on the screen.
// The first frame paints it into the background buffer,
// two more frames are needed until the background buffer
// is flipped to the front in a triple buffer system.

	for (int i=0; i<3; i++) engine_frame();

// Before we can create level entities, a level must be loaded.
// We'll use the small terrain from the techdemo for a level.
// We have to wait one more engine frame to ensure that the level 
// exists and is ready to be filled with level entities.

	level_load("small.hmp");
	engine_frame();

// Now we can create a layer entity for a sky cube at layer 0.
// The SKY flag tells the engine that it's a sky entity, 
// and the CUBE flag tells that the image is a six-sided cube.

	ent_createlayer("blood_gorge+6.tga",_VAR(SKY|CUBE),_VAR(0));

// Let's now create a ball at position (0,0,100).
// The _vec function converts 3 floats to a temporary var vector
// for passing positions to engine functions.

	eBall = ent_create("earth.mdl",_vec(0,0,100),NULL);

// Now let's set the ball's physical properties. 
// We add a small speed to give it a little sidewards kick. 

	phent_settype(eBall,_VAR(PH_RIGID),_VAR(PH_SPHERE));
	phent_setmass(eBall,_VAR(1.0),_VAR(PH_SPHERE));
	phent_setfriction(eBall,_VAR(90.0));
	phent_setelasticity(eBall,_VAR(75.0),_VAR(100.0));
	phent_setdamping(eBall,_VAR(30.0),_VAR(5.0));
	phent_addvelcentral(eBall,_vec(2,2,0));

// A ball game would be no fun without gravity.

	ph_setgravity(_vec(0,0,-500));
	
// We are setting two entity flags in order to cast, but not receive 
// dynamic shadows for the ball

	eBall->flags |= SHADOW|CAST;

// We want to kick the ball by pressing the space key. For this we could scan
// the key state in the main loop; however a more elegant way is a key event.
// We can assign functions to certain events like hitting a key, or a
// collision in the game.

	v(on_space) = (EVENT)Kick;

// Another event: if the ball hits something, a sound shall be played. 
// We set the event function and the enable_friction mask for triggering 
// the event at physics collisions. Note that the minimum speed - 
// the third parameter of phent_setelasticity - determines the
// sensitivity of this event.

	eBall->event = (EVENT)Plop;
	eBall->emask |= ENABLE_FRICTION;

// Now that everything is set up, remove the splash screen.

	pan_remove(pSplash);

// During the main loop we're just moving the camera, as before.

	while (engine_frame()) 
	{

// For the camera movement we now use a more sophisticated method
// with the vec_accelerate() function. It accelerates a speed and
// is not dependent on the frame rate - so we don't need to
// limit the fps in this example. This code is equivalent
// to the built-in camera movement, but uses different keys.

		static VECTOR vSpeed = { 0,0,0 }, vAngularSpeed = { 0,0,0 };
		VECTOR vForce, vMove;

// We need static vectors for the speeds here because they must be 
// preserved between loops.

		vForce.x = -5*(v(key_force).x + v(mouse_force).x);	// pan angle
		vForce.y = 5*(v(key_force).y + v(mouse_force).y);	// tilt angle
		vForce.z = 0;	// roll angle
		vec_accelerate(&vMove,&vAngularSpeed,&vForce,_VAR(0.8));
		vec_add((VECTOR*)&v(camera).pan,&vMove);		

		const int iSpeed = 6;
		vForce.x = iSpeed * (v(key_w) - v(key_s));		// forward
		vForce.y = iSpeed * (v(key_a) - v(key_d));		// sideward
		vForce.z = iSpeed * (v(key_home) - v(key_end));	// upward
		vec_accelerate(&vMove,&vSpeed,&vForce,_VAR(0.5));
		vec_rotate(&vMove,(ANGLE*)&v(camera).pan);
		vec_add((VECTOR*)&v(camera).x,&vMove);
	}

// We don't need to free our created entities, bitmaps and sounds. 
// The engine does this automatically when closing.

	engine_close();
	return 0;
}

// This is our event function for the ball impact.
void Plop(void)
{
// Create a ball impact sound.
// Use a static pointer for creating it only once.

	static SOUND* sPong = snd_create("wham.wav");

// Play the sound at the event entities' position and speed.

	ent_playsound(eBall,sPong,_VAR(100));
}

// This is our event function for hitting the [Space] key.
void Kick(void)
{
// Create a speed vector and rotate it in camera direction.

	VECTOR vSpeed = { _VAR(150),_VAR(0),_VAR(0) };
	vec_rotate(&vSpeed,(ANGLE*)&v(camera).pan);

// Add a vertical speed to give the ball an upwards kick.
	
	vSpeed.z = _VAR(75);

// Now apply the speed to the ball, and play a hit sound.

	phent_addvelcentral(eBall,&vSpeed);
	Plop();
}

#endif // Lesson3 /////////////////////////////////////////////
